package com.allwees.bs.module.fms.entity;

import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.allwees.bs.core.modelbase.constant.ResultCode;
import com.allwees.bs.core.modelbase.entity.BaseEntity;
import com.allwees.bs.module.fms.exception.WithdrawException;
import com.allwees.core.common.util.MoneyUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.Assert;

import javax.persistence.Column;
import java.math.BigDecimal;
import java.util.List;

/**
 * 账务基类
 *
 * @author yangylsky
 * @since 2019-12-31
 *
 */
@Data
@ToString
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public abstract class BaseAccount extends BaseEntity {
	/**
	 * 已结算金额
	 */
	@Column(precision = 8, scale = 2)
	protected BigDecimal settledAmount = BigDecimal.ZERO;

	@Column(length = 48)
	protected String branchUuid;

	/**
	 * 帐号
	 */
	@Column(length = 32)
	protected String accountNo;

	/**
	 * 余额
	 */
	@Column(precision = 10, scale = 2)
	protected BigDecimal balance = BigDecimal.ZERO;

	@Column(length = 4)
	protected String currency;

    /**
     * 绑定手机
     */
	@Column(length = 15)
	private String mobile;

    /**
     * 提现密码
     */
    @JsonIgnore
    @JSONField(serialize = false)
    private String withdrawPassword;

    /**
     * 是否已设置手机号和提现密码
     *
     * @return
     */
    public boolean isSecurityInfoSet() {
    	return StringUtils.isNotBlank(mobile) && StringUtils.isNotBlank(withdrawPassword);
    }

    public boolean checkMerchantAccount(List<MerchantWithdrawAccount> merchantWithdrawAccountList ,String bankAccountNo){
		for (MerchantWithdrawAccount merchantWithdrawAccount : merchantWithdrawAccountList) {
			if(bankAccountNo.equals(merchantWithdrawAccount.getBankAccountNo())){
				return true;
			}
		}
		return false;
	}


	public void verifyWithdrawPassword(PasswordEncoder passwordEncoder, String password) {
		if(!passwordEncoder.matches(getWithdrawPassword(), password)) {
			throw new WithdrawException(ResultCode.MERCHANT_WITHDRAW_WITH_WRONG_PWD,"提现密码错误");
		}
	}

    public void resetWithdrawPassword(PasswordEncoder passwordEncoder, String oldPassword, String newPassword) {
    	verifyWithdrawPassword(passwordEncoder, oldPassword);
    	setWithdrawPassword(newPassword);
    }

	public void assertCanWithdraw(BigDecimal amount) {
		assertCanApplyWithdraw(amount, currency,null,null);
	}

	public void assertCanApplyWithdraw(BigDecimal amount, String bsCurrency, String fee ,String commissionRate) {
		Assert.isTrue(StringUtils.isNotBlank(bsCurrency), "币种不能为空");
		BigDecimal serviceFee = caculateWithdrawFee(amount, bsCurrency,fee);
		BigDecimal commission =  caculateWithdrawExchange(amount, bsCurrency,commissionRate );
		BigDecimal withdrawAmount = MoneyUtil.exchange(amount, bsCurrency, getCurrency());
		Assert.isTrue(MoneyUtil.biggerThan(balance, MoneyUtil.add(withdrawAmount, serviceFee,commission)), "账户余额不足");
	}

	/**
	 * 申请提现操作（扣除了提现金额和手续费）
	 *
	 * @param amount
	 * @return
	 */
	public WithdrawResult applyWithdraw(BigDecimal amount) {
		return applyWithdraw(amount, currency);
	}

	/**
	 * 按指定币种申请提现操作（扣除了提现金额和手续费）
	 *
	 * @param amount
	 * @param
	 * @return
	 */
	public WithdrawResult applyWithdraw(BigDecimal amount, String bsCurrency) {
		Assert.isTrue(StringUtils.isNotBlank(bsCurrency), "币种不能为空");
		assertCanApplyWithdraw(amount, bsCurrency,null,null);
		BigDecimal fee = caculateWithdrawFee(amount, bsCurrency,null);
		BigDecimal withdrawAmount = MoneyUtil.exchange(amount, bsCurrency, getCurrency());
		balance = balance.subtract(withdrawAmount).subtract(fee);
		settledAmount = settledAmount.subtract(withdrawAmount).subtract(fee);
		return new WithdrawResult(bsCurrency, amount, fee,null, bsCurrency, balance, settledAmount,withdrawAmount);
	}


	public WithdrawResult applyWithdraw2(BigDecimal amount, String bsCurrency,String commissionRate, String fee ){
		assertCanApplyWithdraw(amount, bsCurrency,fee,commissionRate);
		//手续费
		BigDecimal servicefee = caculateWithdrawFee(amount, bsCurrency, fee);
		//佣金
		BigDecimal commission =  caculateWithdrawExchange(amount, bsCurrency,commissionRate );

		BigDecimal withdrawAmount = MoneyUtil.exchange(amount, bsCurrency, getCurrency());
		//实际到账金额
		BigDecimal actualAmtForUSD = withdrawAmount.subtract(servicefee).subtract(commission);
		//balance = balance.subtract(withdrawAmount).subtract(servicefee).subtract(commission);
		balance = balance.subtract(amount);
		settledAmount = settledAmount.subtract(amount);
		return new WithdrawResult(bsCurrency, amount, servicefee,commission, bsCurrency, balance,settledAmount, actualAmtForUSD /** 实际到账金额 **/);
	}


	/**
	 * 计算佣金（按指定的币种计算，返回对应当前币种的数额）
	 *
	 * @param amount
	 * @return
	 */
	public BigDecimal caculateWithdrawExchange(BigDecimal amount, String currency,String commissionRate) {
		BigDecimal exchange ;
		if (StringUtils.isEmpty(commissionRate)) {
			commissionRate = "0";
		}
		if (commissionRate.contains("%")) {//按百分比计算
			String[] temp = commissionRate.split("%");
			exchange = MoneyUtil.mul(amount,MoneyUtil.mul(new BigDecimal(temp[0]),new BigDecimal(0.01)));
		}else {//按固定值计算
			exchange = new BigDecimal(commissionRate);
		}
		return exchange == null ? new BigDecimal(0) : exchange;
	}



	/**
	 * 计算手续费（按指定的币种计算，返回对应当前币种的数额）
	 *
	 * @param amount
	 * @return
	 */
	public BigDecimal caculateWithdrawFee(BigDecimal amount, String currency,String fee) {
		BigDecimal servicefee ;
		if (StringUtils.isEmpty(fee)) {
			fee = "0";
		}
		if (fee.contains("%")) {//按百分比计算
			servicefee = MoneyUtil.mul(amount,new BigDecimal(fee));
		} else {//按固定值计算
			servicefee = new BigDecimal(fee) ;
		}
		return servicefee == null ? new BigDecimal(0) : servicefee;
	}

	@Data
	@AllArgsConstructor
	public static class WithdrawResult {
		private String currency;

		private BigDecimal amount;//提现金额

		private BigDecimal fee;//手续费

		private BigDecimal commission;//佣金

		private String balanceCurrency;

		private BigDecimal balance;

		private  BigDecimal settledAmount;//已结算金额

		private BigDecimal withdrawAmount;//实际到账金额
	}
}
